home *** CD-ROM | disk | FTP | other *** search
- From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
- Message-ID: <4gu414$62u@mulga.cs.mu.OZ.AU>
- X-Original-Date: 27 Feb 1996 05:15:16 GMT
- Path: in1.uu.net!bounce-back
- Date: 27 Feb 96 07:29:29 GMT
- Approved: fjh@cs.mu.oz.au
- Newsgroups: comp.std.c++
- Subject: Re: operators new[]/delete[]
- Organization: Comp Sci, University of Melbourne
- References: <313166CF.11C2@orbotech.co.il>
- X-Auth: PGPMoose V1.1 PGP comp.std.c++
- iQBFAgUBMTKy6OEDnX0m9pzZAQEo1AF/Q5+at62o6RsaOD2qkQtPJ4DaGReJKRe5
- sM7uha7CwyYuFBTzxJuuQkXS8J4V5mG1
- =igrN
-
- "Constantine Antonovich:" <const@Orbotech.Co.IL> writes:
-
- > 2. Undefined behavior.
- >
- > Of course, some constructions in a possible program may
- >produce undefined behavior. Nevertheless, even undefined behavior
- >should have some definition.
-
- I disagree. Imposing restrictions on the behaviour of code
- which has "undefined behaviour" would be a very confusing use
- of terminology, and more importantly would place constraints on
- implementors that would prevent efficient implementations.
-
- You may perhaps be able to make a case that certain specific cases
- of undefined behaviour ought to be instead made merely unspecified.
- But in the general case, a write via a stray pointer might cause
- arbitrary instructions to be executed, thus violating any guarantees.
- There is basically no way that an implementation which allows writes
- via stray pointers can prevent this. Preventing stray pointer writes
- is possible, but would have a significant efficiency penalty.
-
- >Let's consider the following code:
- >
- >//----------------------------------------------------------
- > A* ap=new A;
- > B* bp=reinterpret_cast<B*>(ap);
- > delete bp; // #here
- >//----------------------------------------------------------
- >
- >Without any doubt, result of the code executed in "#here" line is
- >undefined. But definitely I wouldn't like, as a result of
- >uncertainty of the behavior, my compiler to send email complaint
- >to some League "C++ compilers against stupidity of the
- >programmers".
-
- You might not like it, but depending on the types `A' and `B',
- this could cause heap corruption on some implementations.
- For example, the compiler might represent pointers to `A' as
- pointing not directly to the start of the memory for `A', but
- instead pointing to some fixed offset before or after the start.
- The reinterpret_case<B*> might not adjust for that offset.
-
- Heap corruption could cause writes through stray pointers,
- which could cause arbitrary code to be executed. The result
- of that could be anything -- sending email complaints is
- unlikely, but can't be ruled out.
-
- >Also I wouldn't like my compiler to recognize
- >incorrectness of the code and silently to call A destructor (after
- >all, bp points to A object, isn't it?) instead of B one. Here I
- >mean that
- >
- > UNDEFINED BEHAVIOR HAS AN ERROR MEANING.
- > UNDEFINED BEHAVIOR ALWAYS RESULTING IN CORRECT EXECUTION OF
- > A CODE WITH UNDEFINED BEHAVIOR, IS FORBIDDEN.
-
- Preventing implementations from doing "the right thing" when
- executing code with undefined behaviour would place unreasonable
- constraints on implementors that would prevent efficient implementations.
-
- For example, a write via a stray pointer might write to some ununsed
- memory, in which case it will have no effect, and the code may continue
- to work. There is basically no way the implementation can avoid this
- other than by checking for stray pointer writes, which as I said before
- would have a significant efficient impact.
-
- > 4. Alignment and memory allocation.
- >
- > In the starting the article example, the following code
- >
- >//----------------------------------------------------------
- > assert(sizeof(A)==sizeof(B));
- >
- > B* bptr=new B[size];
- > A* aptr=(A*)bptr;
- >//----------------------------------------------------------
- >
- >really seems dangerous.
- >
- > Fergus Henderson writes:
- > "This assertion is not guaranteed to succeed.
- > It would take an extremely perverse implementation
- > for it to fail, however, so I think it would be very
- > portable, even though it is not strictly guaranteed
- > to work."
- >
- >This sentence seems to be reasonable but, in deal, this assertion
- >guarantees the correctness ALMOST ALWAYS and under that
- >circumstance this check is absolutely portable.
-
- I don't understand what you are saying here. (This assertion guarantees
- the correctness of what? Under which circumstances?)
-
- > An implementation hasn't to be extremely perverse the
- >assertion condition to fail. It can be very simple one where B
- >class for example has its own operator new[] allocating memory in
- >specific alignment suitable for B but not for any other class and
- >A one particularly (and even that is impossible for compilers
- >still not supporting overloading of operator new[]).
-
- In the test case, A and B were both identical classes (other than the
- class name); I think only a peverse implementation would allocate them
- different sizes.
-
- Your talk about B having `operator new[]' is describing a hypothetical
- peice of source code, not a hypothetical C++ implementation; I don't
- see how it is relevant.
-
- > Fergus Henderson continues:
- >//----------------------------------------------------------
- > B* bptr=new B[size];
- > A* aptr=(A*)bptr;
- >//----------------------------------------------------------
- > "This cast has unspecified behavior. (See 5.2.9
- > [expr.cast.reinterpret]/8.). However, I would
- > expect it to work on most implementations."
- >
- > This article of ANSI draft interprets the operation as
- >unspecified in case of cast from T1 to T2 and back and if there is
- >difference in alignment of T1 and T2. Obviously, that is not our
- >case (at least because definition of allocation function returning
- >suitable for any object alignment).
-
- That's irrelevant, since in your example piece of code, you don't cast
- back to `B *'. 5.2.9/8 says that the result in this case is unspecified.
-
- > Fergus Henderson agrees with Steve Clamage:
- > "This has undefined behaviour. It contravenes 5.3.5
- > [expr.delete]/2, which says that the expression
- > passed to `delete []' must be a pointer to the first
- > element of an array of objects allocated with `new []';
- > this is not the case, because although there once was
- > such an array at that memory location, its lifetime
- > ended when the memory was overwritten by the calls
- > to placement new (see 3.8[basic.life]/1)."
- >
- > There is at least one self-contradictory point in that
- >conclusion. Of course, lifetime of all B objects had been ended,
- >by why does that mean end of the array life?
-
- The lifetime of an array object is distinct from the lifetime of its
- elements. The ending of the lifetime of all the B objects (which you
- did by explciitly calling the destructur) doesn't end the lifetime of
- the array.
-
- What ends the lifetime of the array is reusing the memory (which
- you did by calling placement new). 3.8 is quite clear about this:
- "the lifetime of an array object ... ends when the storage which the array ...
- occupies is reused or released."
-
- >Or in contrary, if
- >end of life-time of B objects means end of life-time of the array,
- >so creation of A objects should mean creation of new array,
- >shouldn't it?.
-
- Yes. But this array was not "created with new []" as required by
- 5.3.5.2, which you quite below, and thus the behaviour is still
- undefined.
-
- > Article 5.3.5.2 of ANSI draft says something slightly
- > different:
- > "...In the second alternative (delete array), the value
- > of the operand of delete shall be a pointer to an
- > array created by a new-expression without a new-placement
- > specification. If not, the behavior is undefined."
- >
- >
- > So delete takes as its argument POINTER TO ARRAY (even objects
- >are not mentioned).
-
- This is indeed a minor error; it has been changed in the January 96
- draft to say "... shall be a pointer to the first element of an array ...".
-
- >No one says that
- > ...pointer passed to delete[] must match the type
- > of the pointer returned by new[]...
- > ...the expression passed to `delete []' must be a
- > pointer to the first element of an array of objects
- > allocated with `new []'...
-
- It does say that the dynamic type of the pointer passed to delete[] must
- match its static type, which is effectively the same thing.
- (See 5.3.5/3.)
-
- > And here we really arrive to the final point. ANSI draft gives
- >no strong array definition to disable ambiguous array
- >interpretation. And above-mentioned common-sense based array
- >understanding has all rights to exist.
-
- The draft is definitely not easy reading, but I think it does define
- things sufficiently well to allow unambiguous interpretation in this
- case.
-
- > Addition to array definition [dcl.array]:
- > Array of N T object represents contiguous amount of
- > memory of suitable size and alignment with N
- > non-overlapping objects of type T placed into the
- > memory with no gaps and each properly aligned.
-
- I think this is already covered by the wording on array lifetimes (3.8)
- and the statement in [dcl.array] that an array object consists of
- contiguously allocated elements. But adding that wording might make
- things clearer.
-
- > Addition to operator delete [expr.delete] ("above" here
- > means all previously said by the standard):
- > In either alternative, the type of the deleted object
- > is evaluated as described above and according to the
- > type of the actual operand.
-
- The draft says that if the dynamic type is different from the static
- type, then the behaviour is undefined. So the above text would be
- a change, not just a clarification. I'm not at all convinced that
- it would be a change for the better. Leaving the behaviour
- undefined in this case gives implementors more flexibility, and
- I think that flexibility is probably more important than defining
- the behaviour of programs like yours which play tricks with memory
- allocation.
-
- --
- Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
- fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
- ---
- [ To submit articles: try just posting with your news-reader.
- If that fails, use mailto:std-c++@ncar.ucar.edu
- FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
- Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
- Comments? mailto:std-c++-request@ncar.ucar.edu.
- ]
-